#include <string.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>

#include <psp2/touch.h>

#include <vita2d.h>

#include "listView.h"
#include "utils.h"
#include "file.h"
#include "ui.h"
#include "config.h"
#include "init.h"
#include "lang.h"
#include "avplaylist.h"

#define COLOR_FOCUS_BG COLOR_ALPHA(AZURE, 0x8F)

static void ListViewReadTouch(ListView *listView);

static int getTouchPos(ListView *listView, int touch_y)
{
    if (!listView || touch_y < 0)
        return -1;

    int item_height = listView->itemView.locations.layout_height + listView->dividerView.locations.layout_height;
    int touch_pos = (touch_y - listView->states.real_current_sy) / item_height;

    return touch_pos;
}

static int getTopPos(ListView *listView)
{
    if (!listView)
        return -1;

    int item_height = listView->itemView.locations.layout_height + listView->dividerView.locations.layout_height;
    int top_pos = (listView->states.real_max_sy - listView->states.real_current_sy) / item_height;

    return top_pos;
}

static int getDrawLines(ListView *listView)
{
    if (!listView)
        return 0;

    int item_height = listView->itemView.locations.layout_height;
    int divider_height = listView->dividerView.locations.layout_height;
    int item_full_height = listView->itemView.locations.layout_height + listView->dividerView.locations.layout_height;

    int lines = (listView->locations.inside_height + divider_height) / item_full_height;

    return lines;
}

static void refreshPosByTopPosBase(int *top_pos, int *focus_pos, int lengh, int draw_lines)
{
    int tmp_top_pos = *top_pos;
    int tmp_focus_pos = *focus_pos;

    if (tmp_top_pos > lengh - draw_lines)
        tmp_top_pos = lengh - draw_lines;
    if (tmp_top_pos < 0)
        tmp_top_pos = 0;

    if (tmp_focus_pos < tmp_top_pos)
        tmp_focus_pos = tmp_top_pos;
    if (tmp_focus_pos > tmp_top_pos + (draw_lines - 1))
        tmp_focus_pos = tmp_top_pos + (draw_lines - 1);

    if (tmp_focus_pos > lengh - 1)
        tmp_focus_pos = lengh - 1;
    if (tmp_focus_pos < 0)
        tmp_focus_pos = 0;

    *top_pos = tmp_top_pos;
    *focus_pos = tmp_focus_pos;
}

static void refreshPosByFocusPosBase(int *top_pos, int *focus_pos, int lengh, int draw_lines)
{
    int tmp_top_pos = *top_pos;
    int tmp_focus_pos = *focus_pos;

    if (tmp_focus_pos > lengh - 1)
        tmp_focus_pos = lengh - 1;
    if (tmp_focus_pos < 0)
        tmp_focus_pos = 0;

    if (tmp_top_pos < tmp_focus_pos - (draw_lines - 1))
        tmp_top_pos = tmp_focus_pos - (draw_lines - 1);
    if (tmp_top_pos > tmp_focus_pos)
        tmp_top_pos = tmp_focus_pos;

    if (tmp_top_pos > lengh - draw_lines)
        tmp_top_pos = lengh - draw_lines;
    if (tmp_top_pos < 0)
        tmp_top_pos = 0;

    *top_pos = tmp_top_pos;
    *focus_pos = tmp_focus_pos;
}

static int isValidClick(ListView *listView, int x, int y)
{ // 判断点击位置是否在列表内
    int limit_sx = listView->locations.inside_sx;
    int limit_sy = listView->states.real_max_sy;
    int limit_dx = listView->locations.inside_dx;
    int limit_dy = listView->states.real_max_dy;

    if (x >= limit_sx && x <= limit_dx && y >= limit_sy && y <= limit_dy)
        return 1;

    return 0;
}

int ListViewGetTopPos(ListView *listView)
{
    if (!listView)
        return -1;

    return listView->states.top_pos;
}

int ListViewGetFocusPos(ListView *listView)
{
    if (!listView)
        return -1;

    return listView->states.focus_pos;
}

int ListViewGetDrawTopPos(ListView *listView)
{
    if (!listView)
        return -1;

    return listView->states.draw_top_pos;
}

int ListViewGetDrawLines(ListView *listView)
{
    if (!listView)
        return 0;

    return listView->states.draw_lines;
}

int ListViewMoveFocusPos(ListView *listView, int move_type)
{
    if (!listView)
        return -1;

    int top_pos = listView->states.top_pos;
    int focus_pos = listView->states.focus_pos;
    int old_focus_pos = focus_pos;
    int lines = listView->states.draw_lines;

    int scroll_type = SCROLL_NONE;

    if (move_type == MOVE_TYPE_PREV)
    {
        focus_pos--;
        scroll_type = SCROLL_DOWN;
    }
    else if (move_type == MOVE_TYPE_NEXT)
    {
        focus_pos++;
        scroll_type = SCROLL_UP;
    }
    if (move_type == MOVE_TYPE_PREV_PAGE)
    {
        focus_pos -= lines;
        scroll_type = SCROLL_DOWN;
    }
    else if (move_type == MOVE_TYPE_NEXT_PAGE)
    {
        focus_pos += lines;
        scroll_type = SCROLL_UP;
    }

    ListViewRefreshPosByFocusPos(listView, top_pos, focus_pos, scroll_type);

    if (old_focus_pos != listView->states.focus_pos)
        listView->itemView.nameTextView.datas.scrolls.scroll_reset = 1;

    return 0;
}

int ListViewGetTouchMode(ListView *listView)
{
    return listView->states.gamepad_mode;
}

void ListViewSetGamepadMode(ListView *listView, int gamepad_mode)
{
    if (!listView->states.gamepad_mode && gamepad_mode)
    {
        int top_pos = listView->states.draw_top_pos;
        int focus_pos = listView->states.focus_pos;
        ListViewRefreshPosByTopPos(listView, top_pos, focus_pos, SCROLL_NONE);
    }
    listView->states.gamepad_mode = gamepad_mode;
}

void ListViewFixScrollRealFinalSy(ListView *listView)
{
    if (listView->states.real_final_sy > listView->states.real_max_sy)
        listView->states.real_final_sy = listView->states.real_max_sy;
    else if (listView->states.real_final_sy < listView->states.real_min_sy)
        listView->states.real_final_sy = listView->states.real_min_sy;
}

void ListViewSetDefaultScrollStepPixls(ListView *listView)
{
    listView->states.scroll_step_pixls = (listView->states.real_final_sy - listView->states.real_current_sy) / 10;
}

int ListViewIsScrolling(ListView *listView)
{ // 判断列表是否在滚动中
    return listView->states.real_current_sy != listView->states.real_final_sy;
}

void ListViewStopScroll(ListView *listView)
{
    listView->states.real_final_sy = listView->states.real_current_sy;
    listView->states.inertia_ori_scroll_pixls = 0;
    listView->states.inertia_scroll_pixls = 0;
    listView->states.scroll_step_pixls = 0;
}

void ListViewSetOnItemClikListener(ListView *listView, ListViewOnClick onItemClick)
{
    listView->evens.onItemClick = onItemClick;
}

void ListViewSetOnItemLongClikListener(ListView *listView, ListViewOnClick onItemLongClick)
{
    listView->evens.onItemLongClick = onItemLongClick;
}

int ListViewGetTopItemViewSyOffset(ListView *listView)
{
    int item_full_height = listView->itemView.locations.layout_height + listView->dividerView.locations.layout_height;
    int differ = listView->states.real_max_sy - listView->states.real_current_sy;
    int sy_offset = differ % item_full_height;

    return sy_offset;
}

void ListViewSetTopItemViewSyOffset(ListView *listView, int y_offset)
{
    int old_y_offset = ListViewGetTopItemViewSyOffset(listView);
    listView->states.real_final_sy += (old_y_offset - y_offset);
    ListViewFixScrollRealFinalSy(listView);
}

int ListViewGetTopItemViewSy(ListView *listView)
{
    int sy_offset = ListViewGetTopItemViewSyOffset(listView);
    int top_item_sy = listView->states.real_max_sy - sy_offset;

    return top_item_sy;
}

void ListViewSetLayoutXY(ListView *listView, int sx, int sy)
{
    if (!listView)
        return;

    int differ_x = sx - listView->locations.layout_sx;
    int differ_y = sy - listView->locations.layout_sy;

    if (differ_x != 0)
    {
        listView->locations.layout_sx += differ_x;
        listView->locations.layout_dx += differ_x;
        listView->locations.inside_sx += differ_x;
        listView->locations.inside_dx += differ_x;
    }

    if (differ_y != 0)
    {
        listView->locations.layout_sy += differ_y;
        listView->locations.layout_dy += differ_y;
        listView->locations.inside_sy += differ_y;
        listView->locations.inside_dy += differ_y;

        listView->states.real_min_sy += differ_y;
        listView->states.real_max_sy += differ_y;
        listView->states.real_min_dy += differ_y;
        listView->states.real_max_dy += differ_y;
        listView->states.real_current_sy += differ_y;
        listView->states.real_final_sy += differ_y;
    }
}

void ListViewAlignTopItem(ListView *listView)
{
    int list_length = listView->callbacks.getListLengh(listView->list);

    if (listView->states.focus_pos == 0)
    {
        listView->states.real_final_sy = listView->states.real_max_sy;
    }
    else if (listView->states.focus_pos == list_length - 1)
    {
        listView->states.real_final_sy = listView->states.real_min_sy;
    }
    else
    {
        int item_full_height = listView->itemView.locations.layout_height + listView->dividerView.locations.layout_height;
        int differ = listView->locations.inside_sy - listView->states.real_final_sy;
        int remainder = differ % item_full_height;

        if (remainder > 0)
        {
            listView->states.real_final_sy -= (item_full_height - remainder);
            ListViewFixScrollRealFinalSy(listView);
        }
    }
}

void ListViewAlignBottomItem(ListView *listView)
{
    int list_length = listView->callbacks.getListLengh(listView->list);

    if (listView->states.focus_pos == 0)
    {
        listView->states.real_final_sy = listView->states.real_max_sy;
    }
    else if (listView->states.focus_pos == list_length - 1)
    {
        listView->states.real_final_sy = listView->states.real_min_sy;
    }
    else
    {
        int item_full_height = listView->itemView.locations.layout_height + listView->dividerView.locations.layout_height;
        int differ = listView->locations.inside_dy - listView->states.real_final_sy;
        int remainder = (differ + listView->dividerView.locations.layout_height) % item_full_height;

        if (remainder > 0)
        {
            listView->states.real_final_sy += remainder;
            ListViewFixScrollRealFinalSy(listView);
        }
    }
}

void ListViewScrollUp(ListView *listView, int n_item)
{
    int item_full_height = listView->itemView.locations.layout_height + listView->dividerView.locations.layout_height;
    int scroll_height = n_item * item_full_height;

    listView->states.real_final_sy = listView->states.real_final_sy - scroll_height;
    ListViewFixScrollRealFinalSy(listView);
    ListViewSetDefaultScrollStepPixls(listView);
}

void ListViewScrollDown(ListView *listView, int n_item)
{
    int item_full_height = listView->itemView.locations.layout_height + listView->dividerView.locations.layout_height;
    int scroll_height = n_item * item_full_height;

    listView->states.real_final_sy = listView->states.real_final_sy + scroll_height;
    ListViewFixScrollRealFinalSy(listView);
    ListViewSetDefaultScrollStepPixls(listView);
}

void ListViewScrollToFirst(ListView *listView)
{
    listView->states.real_final_sy = listView->states.real_max_sy;
    ListViewSetDefaultScrollStepPixls(listView);
}

void ListViewScrollToLast(ListView *listView)
{
    listView->states.real_final_sy = listView->states.real_min_sy;
    ListViewSetDefaultScrollStepPixls(listView);
}

static void refreshPosBase(ListView *listView, int top_pos, int focus_pos, int scroll_type)
{
    int list_length = listView->callbacks.getListLengh(listView->list);
    int old_focus_pos = listView->states.focus_pos;
    listView->states.top_pos = top_pos;
    listView->states.focus_pos = focus_pos;

    if (listView->states.real_max_height > listView->locations.inside_height)
    {
        int item_full_height = listView->itemView.locations.layout_height + listView->dividerView.locations.layout_height;

        listView->states.real_final_sy = listView->states.real_max_sy - top_pos * item_full_height;

        ListViewFixScrollRealFinalSy(listView);

        if (listView->states.focus_pos == 0)
            ListViewAlignTopItem(listView);
        else if (listView->states.focus_pos == list_length - 1)
            ListViewAlignBottomItem(listView);
        else if (listView->states.focus_pos == listView->states.top_pos)
            ListViewAlignBottomItem(listView);
        else if (listView->states.focus_pos == (listView->states.top_pos + (listView->states.draw_lines - 1)))
            ListViewAlignTopItem(listView);
        else if (scroll_type == SCROLL_DOWN || focus_pos < old_focus_pos)
            ListViewAlignBottomItem(listView);
        else if (scroll_type == SCROLL_UP || focus_pos > old_focus_pos)
            ListViewAlignTopItem(listView);

        if (scroll_type == SCROLL_NONE)
            listView->states.real_current_sy = listView->states.real_final_sy;
    }
    else
    {
        listView->states.real_current_sy = listView->states.real_max_sy;
        listView->states.real_final_sy = listView->states.real_current_sy;
    }

    ListViewSetDefaultScrollStepPixls(listView);
}

void ListViewRefreshPosByTopPos(ListView *listView, int top_pos, int focus_pos, int scroll_type)
{
    int list_length = listView->callbacks.getListLengh(listView->list);
    refreshPosByTopPosBase(&top_pos, &focus_pos, list_length, listView->states.draw_lines);
    refreshPosBase(listView, top_pos, focus_pos, scroll_type);
}

void ListViewRefreshPosByFocusPos(ListView *listView, int top_pos, int focus_pos, int scroll_type)
{
    int list_length = listView->callbacks.getListLengh(listView->list);
    refreshPosByFocusPosBase(&top_pos, &focus_pos, list_length, listView->states.draw_lines);
    refreshPosBase(listView, top_pos, focus_pos, scroll_type);
}

void ListViewRefreshList(ListView *listView, void *list)
{
    if (!listView || !list)
        return;

    listView->list = list;

    ItemView *itemView = &listView->itemView;
    int item_height = listView->itemView.locations.layout_height;
    int divider_height = listView->dividerView.locations.layout_height;
    int item_full_height = item_height + divider_height;

    int list_length = listView->callbacks.getListLengh(listView->list);
    int max_inside_height = listView->locations.layout_height - listView->locations.padding_top - listView->locations.padding_bottom;

    if (list_length > 0)
        listView->states.real_max_height = item_full_height * list_length - divider_height;
    else
        listView->states.real_max_height = 0;

    if (listView->states.real_max_height < max_inside_height)
        listView->locations.inside_height = listView->states.real_max_height;
    else
        listView->locations.inside_height = max_inside_height;
    listView->locations.inside_dy = listView->locations.inside_sy + listView->locations.inside_height;

    listView->states.real_min_sy = listView->locations.inside_dy - listView->states.real_max_height;
    listView->states.real_max_sy = listView->locations.inside_sy;
    listView->states.real_min_dy = listView->locations.inside_dy;
    listView->states.real_max_dy = listView->locations.inside_sy + listView->states.real_max_height;
    listView->states.real_current_sy = listView->states.real_max_sy;
    listView->states.real_final_sy = listView->states.real_current_sy;

    listView->states.inertia_ori_scroll_pixls = 0;
    listView->states.inertia_scroll_pixls = 0;
    listView->states.scroll_step_pixls = 0;

    listView->states.draw_lines = getDrawLines(listView);

    itemView->nameTextView.datas.scrolls.scroll_reset = 1;

    ListViewRefreshPosByFocusPos(listView, listView->states.top_pos, listView->states.focus_pos, SCROLL_NONE);
}

ListView *NewListView(ListViewParams *params, ListViewCallbacks *callbacks, void *list)
{
    if (!params || !callbacks || !list)
        return NULL;

    ListView *listView = (ListView *)malloc(sizeof(ListView));
    if (!listView)
        return NULL;

    memset(listView, 0, sizeof(ListView));
    memcpy(&listView->params, params, sizeof(ListViewParams));
    memcpy(&listView->callbacks, callbacks, sizeof(ListViewCallbacks));

    listView->locations.layout_sx = params->layout_sx;
    listView->locations.layout_sy = params->layout_sy;
    listView->locations.layout_dx = params->layout_sx + params->layout_width;
    listView->locations.layout_dy = params->layout_sy + params->layout_height;
    listView->locations.layout_width = params->layout_width;
    listView->locations.layout_height = params->layout_height;
    listView->locations.padding_left = params->padding_left;
    listView->locations.padding_right = params->padding_right;
    listView->locations.padding_top = params->padding_top;
    listView->locations.padding_bottom = params->padding_bottom;
    listView->locations.inside_sx = params->layout_sx + params->padding_left;
    listView->locations.inside_sy = params->layout_sy + params->padding_top;
    listView->locations.inside_dx = listView->locations.layout_dx - params->padding_right;
    listView->locations.inside_dy = listView->locations.layout_dy - params->padding_bottom;
    listView->locations.inside_width = listView->locations.inside_dx - listView->locations.inside_sx;
    listView->locations.inside_height = listView->locations.inside_dy - listView->locations.inside_sy;

    ItemView *itemView = &listView->itemView;
    itemView->locations.padding_left = 4;
    itemView->locations.padding_right = 4;
    itemView->locations.padding_top = 4;
    itemView->locations.padding_bottom = 4;
    itemView->locations.layout_width = listView->locations.inside_width;
    itemView->colors.bg_color = params->itemview_bg_color;
    itemView->colors.clicked_color = COLOR_ALPHA(AZURE, 0xEF);
    itemView->params.visibility = 1;

    int item_inside_height = 0;

    CheckBoxView *checkBoxView = &itemView->checkBoxView;
    TextView *infoTextView = &itemView->infoTextView;
    TextView *nameTextView = &itemView->nameTextView;
    ImageView *imageView = &itemView->imageView;

    nameTextView->datas.text_size = 1.0;
    nameTextView->datas.text_color = WHITE;
    nameTextView->locations.padding_left = 4;
    nameTextView->locations.padding_right = 4;
    nameTextView->locations.padding_top = 4;
    nameTextView->locations.padding_bottom = 2;
    nameTextView->locations.layout_height = nameTextView->locations.padding_top + DEFAULT_LINE_HEIGHT * nameTextView->datas.text_size + nameTextView->locations.padding_bottom;
    nameTextView->colors.bg_color = 0;
    nameTextView->params.visibility = 1;

    item_inside_height += nameTextView->locations.layout_height;

    if (params->enable_info)
    {
        infoTextView->datas.text_size = 0.8;
        infoTextView->datas.text_color = LITEGRAY;
        infoTextView->locations.padding_left = 4;
        infoTextView->locations.padding_right = 4;
        infoTextView->locations.padding_top = 2;
        infoTextView->locations.padding_bottom = 4;
        infoTextView->locations.layout_height = infoTextView->locations.padding_top + DEFAULT_LINE_HEIGHT * infoTextView->datas.text_size + infoTextView->locations.padding_bottom;
        infoTextView->colors.bg_color = 0;
        infoTextView->params.visibility = 1;

        item_inside_height += infoTextView->locations.layout_height;
    }

    itemView->locations.layout_height = itemView->locations.padding_top + item_inside_height + itemView->locations.padding_bottom;
    if (itemView->locations.layout_height < 54)
    {
        itemView->locations.layout_height = 54;
        itemView->locations.padding_top = (54.f - item_inside_height) / 2;
        itemView->locations.padding_bottom = itemView->locations.padding_top;
    }

    int max_free_height = itemView->locations.layout_height - itemView->locations.padding_top - itemView->locations.padding_bottom;

    if (params->enable_image)
    {
        imageView->locations.padding_left = 4;
        imageView->locations.padding_right = 4;
        int image_height = MIN(38, max_free_height);
        int image_width = image_height;
        imageView->locations.layout_height = max_free_height;
        imageView->locations.layout_width = imageView->locations.padding_left + image_width + imageView->locations.padding_right;
        imageView->locations.padding_top = (imageView->locations.layout_height - image_height) / 2;
        imageView->locations.padding_bottom = imageView->locations.padding_top;
        imageView->colors.bg_color = 0;
        imageView->params.visibility = 1;
    }

    if (params->enable_checkBox)
    {
        checkBoxView->datas.images[0] = vita2d_load_PNG_file(CHECKBOX_UNCHECKED_PATH);
        checkBoxView->datas.images[1] = vita2d_load_PNG_file(CHECKBOX_CHECKED_PATH);
        checkBoxView->locations.padding_left = 4;
        checkBoxView->locations.padding_right = 4;
        int checkBox_image_height = MIN(28, max_free_height);
        int checkBox_image_width = checkBox_image_height;
        checkBoxView->locations.layout_height = max_free_height;
        checkBoxView->locations.layout_width = checkBoxView->locations.padding_left + checkBox_image_width + checkBoxView->locations.padding_right;
        checkBoxView->locations.padding_top = (checkBoxView->locations.layout_height - checkBox_image_height) / 2;
        checkBoxView->locations.padding_bottom = checkBoxView->locations.padding_top;
        checkBoxView->colors.bg_color = 0;
        checkBoxView->params.visibility = 0;
    }

    nameTextView->locations.layout_width = itemView->locations.layout_width - itemView->locations.padding_left - itemView->locations.padding_right - imageView->locations.layout_width - checkBoxView->locations.layout_width;

    TextView *dividerView = &listView->dividerView;
    dividerView->locations.padding_left = 0;
    dividerView->locations.padding_right = 0;
    dividerView->locations.layout_width = itemView->locations.layout_width - dividerView->locations.padding_left - dividerView->locations.padding_right;
    dividerView->locations.layout_height = 2;
    dividerView->colors.bg_color = COLOR_ALPHA(WHITE, 0xAF);
    dividerView->params.visibility = 1;

    ListViewRefreshList(listView, list);

    return listView;
}

void DestroyListView(ListView *listView)
{
    if (!listView)
        return;

    int i;
    Image **images = listView->itemView.checkBoxView.datas.images;
    vita2d_wait_rendering_done();
    for (i = 0; i < 2; i++)
    {
        if (images[i])
            vita2d_free_texture(images[i]);
    }
    free(listView);
}

void ListViewRefreshRealSy(ListView *listView)
{
    if (listView->states.inertia_scroll_pixls != 0)
    {
        int scroll_pixls = listView->states.inertia_scroll_pixls;

        if (scroll_pixls < 0)
        {
            if (listView->states.scroll_step_pixls >= 0)
                listView->states.scroll_step_pixls = (float)listView->states.inertia_ori_scroll_pixls / 10.f;

            if (scroll_pixls < (float)listView->states.inertia_ori_scroll_pixls / 5.f)
            {
                scroll_pixls = (float)listView->states.inertia_scroll_pixls * 9.f / 10.f;
                listView->states.inertia_scroll_pixls = scroll_pixls;
            }
            else
            {
                if (scroll_pixls < -20)
                    scroll_pixls = -20;
                listView->states.scroll_step_pixls = -1;
                listView->states.inertia_ori_scroll_pixls = 0;
                listView->states.inertia_scroll_pixls = 0;
            }
        }
        else if (scroll_pixls > 0)
        {
            if (listView->states.scroll_step_pixls <= 0)
                listView->states.scroll_step_pixls = (float)listView->states.inertia_ori_scroll_pixls / 10.f;

            if (scroll_pixls > (float)listView->states.inertia_ori_scroll_pixls / 5.f)
            {
                scroll_pixls = (float)listView->states.inertia_scroll_pixls * 9.f / 10.f;
                listView->states.inertia_scroll_pixls = scroll_pixls;
            }
            else
            {
                if (scroll_pixls > 20)
                    scroll_pixls = 20;
                listView->states.scroll_step_pixls = 1;
                listView->states.inertia_ori_scroll_pixls = 0;
                listView->states.inertia_scroll_pixls = 0;
            }
        }

        listView->states.real_final_sy = listView->states.real_current_sy + scroll_pixls;
        ListViewFixScrollRealFinalSy(listView);
    }

    if (listView->states.real_current_sy != listView->states.real_final_sy)
    {
        int sy_differ_pixls = listView->states.real_final_sy - listView->states.real_current_sy;
        int scroll_step_pixls = listView->states.scroll_step_pixls;

        if (sy_differ_pixls < 0)
        {
            if (scroll_step_pixls < sy_differ_pixls)
                scroll_step_pixls = sy_differ_pixls;
            else if (scroll_step_pixls > -1)
                scroll_step_pixls = -1;
        }
        else if (sy_differ_pixls > 0)
        {
            if (scroll_step_pixls > sy_differ_pixls)
                scroll_step_pixls = sy_differ_pixls;
            else if (scroll_step_pixls < 1)
                scroll_step_pixls = 1;
        }
        else
        {
            scroll_step_pixls = 0;
        }
        printf("scroll_step_pixls: %d\n", scroll_step_pixls);

        listView->states.real_current_sy += scroll_step_pixls;
    }
}

void ListViewDrawItem(ItemView *itemView, int x, int y, int parent_sx, int parent_sy, int parent_dx, int parent_dy)
{
    ImageView *imageView = &itemView->imageView;
    TextView *nameTextView = &itemView->nameTextView;
    TextView *infoTextView = &itemView->infoTextView;
    CheckBoxView *checkBoxView = &itemView->checkBoxView;

    int parent_clip_sx = (x < parent_sx) ? parent_sx : x;
    int parent_clip_sy = (y < parent_sy) ? parent_sy : y;
    int ori_dx = x + itemView->locations.layout_width;
    int ori_dy = y + itemView->locations.layout_height;
    int parent_clip_dx = (ori_dx > parent_dx) ? parent_dx : ori_dx;
    int parent_clip_dy = (ori_dy > parent_dy) ? parent_dy : ori_dy;

    int sx = x + itemView->locations.padding_left;
    int sy = y + itemView->locations.padding_top;
    int dx = x + itemView->locations.layout_width - itemView->locations.padding_right;
    int dy = y + itemView->locations.layout_height - itemView->locations.padding_bottom;

    int inside_clip_sx = sx < parent_sx ? parent_sx : sx;
    int inside_clip_sy = sy < parent_sy ? parent_sy : sy;
    int inside_clip_dx = dx > parent_dx ? parent_dx : dx;
    int inside_clip_dy = dy > parent_dy ? parent_dy : dy;

    vita2d_enable_clipping();
    vita2d_set_clip_rectangle(parent_clip_sx, parent_clip_sy, parent_clip_dx, parent_clip_dy);

    if (itemView->colors.bg_color)
        vita2d_draw_rectangle(x, y, itemView->locations.layout_width, itemView->locations.layout_height, itemView->colors.bg_color);

    if (itemView->clicks.current)
        vita2d_draw_rectangle(x, y, itemView->locations.layout_width, itemView->locations.layout_height, itemView->colors.clicked_color);

    vita2d_set_clip_rectangle(inside_clip_sx, inside_clip_sy, inside_clip_dx, inside_clip_dy);

    if (imageView->params.visibility)
    {
        int image_sx = sx + imageView->locations.padding_left;
        int image_sy = sy + imageView->locations.padding_top;
        Image *image_tex = imageView->datas.image;
        if (image_tex)
        {
            int tex_width = vita2d_texture_get_width(image_tex);
            int tex_height = vita2d_texture_get_height(image_tex);
            int image_width = imageView->locations.layout_width - imageView->locations.padding_left - imageView->locations.padding_right;
            int image_height = imageView->locations.layout_height - imageView->locations.padding_top - imageView->locations.padding_bottom;
            float scale_x = (float)image_width / (float)tex_width;
            float scale_y = (float)image_height / (float)tex_height;
            vita2d_draw_texture_scale(image_tex, image_sx, image_sy, scale_x, scale_y);
        }
        sx += imageView->locations.layout_width;
    }

    int current_sx = sx;
    int current_sy = sy;

    if (nameTextView->params.visibility)
    {
        int name_sx = current_sx + nameTextView->locations.padding_left;
        int name_sy = current_sy + nameTextView->locations.padding_top;
        int inside_width = nameTextView->locations.layout_width - nameTextView->locations.padding_left - nameTextView->locations.padding_right;
        int inside_height = nameTextView->locations.layout_height - nameTextView->locations.padding_top - nameTextView->locations.padding_bottom;
        int name_dx = name_sx + inside_width;
        int name_dy = name_sy + inside_height;
        uint32_t color = nameTextView->datas.text_color;

        int clip_sx = name_sx < inside_clip_sx ? inside_clip_sx : name_sx;
        int clip_sy = name_sy < inside_clip_sy ? inside_clip_sy : name_sy;
        int clip_dx = name_dx > inside_clip_dx ? inside_clip_dx : name_dx;
        int clip_dy = name_dy > inside_clip_dy ? inside_clip_dy : name_dy;

        if (nameTextView->datas.scrolls.scroll_reset)
        {
            nameTextView->datas.scrolls.scroll_count = 0;
            nameTextView->datas.scrolls.scroll_x_off = 0;
            nameTextView->datas.scrolls.scroll_reset = 0;
        }

        if (nameTextView->datas.scrolls.scroll_enable)
        {
            int text_width = vita2d_pgf_text_width(UiGetFont(), nameTextView->datas.text_size, nameTextView->datas.text);

            if (text_width > inside_width)
            {
                if (nameTextView->datas.scrolls.scroll_count < 60)
                {
                    nameTextView->datas.scrolls.scroll_x_off = 0;
                }
                else if (nameTextView->datas.scrolls.scroll_count < text_width + 90)
                {
                    nameTextView->datas.scrolls.scroll_x_off--;
                }
                else if (nameTextView->datas.scrolls.scroll_count < text_width + 120)
                {
                    color = (color & 0x00FFFFFF) | ((((color >> 24) * (nameTextView->datas.scrolls.scroll_count - text_width - 90)) / 30) << 24); // fade-in in 0.5s
                    nameTextView->datas.scrolls.scroll_x_off = 0;
                }
                else
                {
                    nameTextView->datas.scrolls.scroll_count = 0;
                }

                nameTextView->datas.scrolls.scroll_count++;

                name_sx += nameTextView->datas.scrolls.scroll_x_off;
            }
        }

        vita2d_set_clip_rectangle(clip_sx, clip_sy, clip_dx, clip_dy);

        vita2d_pgf_draw_text(UiGetFont(), name_sx, name_sy + DEFAULT_FONT_HEIGHT * nameTextView->datas.text_size, color, nameTextView->datas.text_size, nameTextView->datas.text);
        sx += nameTextView->locations.layout_width;
        current_sy += nameTextView->locations.layout_height;

        vita2d_set_clip_rectangle(inside_clip_sx, inside_clip_sy, inside_clip_dx, inside_clip_dy);
    }

    if (infoTextView->params.visibility)
    {
        int date_sx = current_sx + infoTextView->locations.padding_left;
        int date_sy = current_sy + infoTextView->locations.padding_top;
        int draw_width = vita2d_pgf_draw_text(UiGetFont(), date_sx, date_sy + DEFAULT_FONT_HEIGHT * infoTextView->datas.text_size, infoTextView->datas.text_color, infoTextView->datas.text_size, infoTextView->datas.text);
        infoTextView->locations.layout_width = infoTextView->locations.padding_left + draw_width + infoTextView->locations.padding_right;
        current_sx += infoTextView->locations.layout_width;
    }

    if (checkBoxView->params.visibility)
    {
        int checkBox_sx = dx - checkBoxView->locations.layout_width + checkBoxView->locations.padding_left;
        int checkBox_sy = sy + checkBoxView->locations.padding_top;
        Image *image_tex = checkBoxView->datas.images[checkBoxView->datas.is_checked];
        if (image_tex)
        {
            int tex_width = vita2d_texture_get_width(image_tex);
            int tex_height = vita2d_texture_get_height(image_tex);
            int image_width = checkBoxView->locations.layout_width - checkBoxView->locations.padding_left - checkBoxView->locations.padding_right;
            int image_height = checkBoxView->locations.layout_height - checkBoxView->locations.padding_top - checkBoxView->locations.padding_bottom;
            float scale_x = (float)image_width / (float)tex_width;
            float scale_y = (float)image_height / (float)tex_height;
            vita2d_draw_texture_scale(image_tex, checkBox_sx, checkBox_sy, scale_x, scale_y);
        }
        sx += checkBoxView->locations.layout_width;
    }

    vita2d_disable_clipping();
}

void ListViewDraw(ListView *listView)
{
    if (!listView)
        return;

    vita2d_draw_rectangle(listView->locations.layout_sx, listView->locations.layout_sy, listView->locations.layout_width, listView->locations.layout_height, listView->params.listview_bg_color);

    if (!listView->list)
        return;

    ListViewReadTouch(listView);
    ListViewRefreshRealSy(listView);

    listView->states.draw_top_pos = getTopPos(listView);
    int top_pos = listView->states.draw_top_pos;
    int focus_pos = listView->states.focus_pos;

    void *entry = listView->callbacks.getEntryByNumber(listView->list, top_pos);
    if (!entry)
        return;

    ItemView *itemView = &listView->itemView;
    TextView *dividerView = &listView->dividerView;

    int gamepad_mode = ListViewGetTouchMode(listView);
    int list_length = listView->callbacks.getListLengh(listView->list);
    int item_full_height = listView->itemView.locations.layout_height + listView->dividerView.locations.layout_height;

    int sx = listView->locations.inside_sx;
    int sy = ListViewGetTopItemViewSy(listView);

    int i;
    for (i = top_pos; i < list_length; i++)
    {
        if (sy >= listView->locations.layout_dy)
            break;

        itemView->clicks.current = 0;
        if (i == focus_pos)
        {
            if (gamepad_mode || listView->clicks.onclick || listView->clicks.onlongclick)
                itemView->clicks.current = 1;
            itemView->nameTextView.datas.scrolls.scroll_enable = 1;
        }
        else
        {
            itemView->nameTextView.datas.scrolls.scroll_enable = 0;
        }

        itemView->imageView.params.visibility = 0;
        if (listView->params.enable_image && listView->callbacks.getImageViewData)
        {
            listView->callbacks.getImageViewData(&itemView->imageView, listView->list, entry, i);
            itemView->imageView.params.visibility = 1;
        }

        itemView->nameTextView.params.visibility = 1;
        if (listView->callbacks.getNameViewData)
            listView->callbacks.getNameViewData(&itemView->nameTextView, listView->list, entry, i);
        else
            itemView->nameTextView.datas.text = NULL;

        itemView->infoTextView.params.visibility = 0;
        if (listView->params.enable_info && listView->callbacks.getInfoViewData)
        {
            listView->callbacks.getInfoViewData(&itemView->infoTextView, listView->list, entry, i);
            itemView->infoTextView.params.visibility = 1;
        }

        itemView->checkBoxView.params.visibility = 0;
        if (listView->params.enable_checkBox && listView->callbacks.getCheckBoxViewData)
        {
            listView->callbacks.getCheckBoxViewData(&itemView->checkBoxView, listView->list, entry, i);
        }

        ListViewDrawItem(itemView, sx, sy, listView->locations.inside_sx, listView->locations.inside_sy, listView->locations.inside_dx, listView->locations.inside_dy);

        vita2d_enable_clipping();
        vita2d_set_clip_rectangle(listView->locations.inside_sx, listView->locations.inside_sy, listView->locations.inside_dx, listView->locations.inside_dy);

        dividerView->params.visibility = 0;
        if (!listView->params.disable_divider && i < list_length - 1)
            dividerView->params.visibility = 1;

        if (dividerView->params.visibility)
        {
            int divider_sx = sx + dividerView->locations.padding_left;
            int divider_sy = sy + itemView->locations.layout_height;
            vita2d_draw_rectangle(divider_sx, divider_sy, dividerView->locations.layout_width, dividerView->locations.layout_height, dividerView->colors.bg_color);
        }

        vita2d_disable_clipping();

        sy += item_full_height;
        entry = listView->callbacks.getNextEntry(listView->list, entry, i);
    }
}

static void ListViewReadTouch(ListView *listView)
{
    static int last_y_scroll_total_pixls = 0;
    static int disable_onclick = 0;
    static int disable_scroll = 0;

    TouchReaport *touch_reaport = &touch_pad.reaports[0];
    TouchStates *touch_states = &touch_reaport->states;
    TouchData *old_touch = &touch_reaport->old;
    TouchData *current_touch = &touch_reaport->current;

    if (touch_pad.back_event_mode)
    {
        return;
    }

    if (touch_states->pressed_touched)
    { // 第一次触摸
        if (isValidClick(listView, current_touch->x, current_touch->y))
        {
            ListViewSetGamepadMode(listView, 0);
            if (ListViewIsScrolling(listView))
                disable_onclick = 1;
            ListViewStopScroll(listView);
            int touch_pos = getTouchPos(listView, current_touch->y);
            listView->states.focus_pos = touch_pos;
            listView->itemView.nameTextView.datas.scrolls.scroll_reset = 1;
        }
    }

    if (touch_states->released_touched && old_touch->motionless_hold_count > 3 && old_touch->hold_count < 10)
    { // 点击事件
        if (!disable_onclick && isValidClick(listView, old_touch->x, old_touch->y))
        {
            int touch_pos = getTouchPos(listView, old_touch->y);
            listView->states.focus_pos = touch_pos;
            listView->clicks.onclick = 1;
            return;
        }
    }

    if (touch_states->current_touched && current_touch->motionless_hold_count > 20)
    { // 长按事件
        if (!disable_onclick && isValidClick(listView, current_touch->x, current_touch->y))
        {
            int touch_pos = getTouchPos(listView, current_touch->y);
            listView->states.focus_pos = touch_pos;
            listView->clicks.onlongclick = 1;
            disable_onclick = 1;
            disable_scroll = 1;
            return;
        }
    }

    if (!disable_scroll)
    {
        if (touch_states->current_y_scrolled)
        {
            if (isValidClick(listView, current_touch->x, current_touch->y))
            {
                listView->states.real_final_sy += current_touch->y_scroll_cur_pixls;
                ListViewFixScrollRealFinalSy(listView);
                listView->states.scroll_step_pixls = current_touch->y_scroll_cur_pixls;
                disable_onclick = 1;
            }
        }
        else if (touch_states->released_y_scrolled)
        {
            if (isValidClick(listView, old_touch->x, old_touch->y))
                last_y_scroll_total_pixls = old_touch->y_scroll_total_pixls;
        }
    }

    if (touch_states->released_touched)
    {
        if (old_touch->motionless_hold_count < 3)
        {
            if (last_y_scroll_total_pixls < -10 || last_y_scroll_total_pixls > 10)
            {
                listView->states.inertia_ori_scroll_pixls = last_y_scroll_total_pixls;
                listView->states.inertia_scroll_pixls = last_y_scroll_total_pixls;
                listView->states.scroll_step_pixls = last_y_scroll_total_pixls / N_PIXLS_BUFS;
            }
        }
        last_y_scroll_total_pixls = 0;
        disable_onclick = 0;
        disable_scroll = 0;
    }
}

void ListViewEvent(ListView *listView)
{
    if (listView->clicks.onclick)
    {
        if (listView->evens.onItemClick)
            listView->evens.onItemClick(listView);
        listView->clicks.onclick = 0;
    }

    if (listView->clicks.onlongclick)
    {
        if (listView->evens.onItemLongClick)
            listView->evens.onItemLongClick(listView);
        listView->clicks.onlongclick = 0;
    }
}
